#   This file is part of emesene.
#
#    Eval plugin is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    Eval plugin is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with emesene; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#Changelog:
#0.4.8:
#-Fix Back consinstency for PyGtk in setting tooltips of a ToolItem

#0.4.7.1:
#-Try to solve ('Exception importing LogConversation\nNo module named paths', 'PluginManager') in Opensuse 10.3 64 bit
# with paths importing code from aaPluginDownloader

#0.4.7:
#-Fix bug: Controller has not attribute debug.

#0.4.6:
#-Received custom emoticons are logged with the string in fields data in
# the tag <object type="application/x-emesene-emoticon" class="%s" data="%s"></object>
#-With group conversation logger change automatically in the right file 
# where to log: emailRemote1-emailRemote2... .html

#0.1 -> 0.4.5:
#-Store in file paths.CONFIG_DIR join controller.config.getCurrentUser() join html_logs join emailRemote
#-utf-8 coding of html logs
#-Added a button to conversation toolbar to view logs in current browser
#Logging Capability:
#-Send/received messages
#-OfflineReceived messages
#-File Transfers acceptation

VERSION = '0.4.8'
import Plugin
import dialog
import os
import time
import emesenelib
import desktop
import gtk

#From aaPluginDownloader
try:
	import paths
	CONFIG_PATH = paths.CONFIG_DIR
except:
	import emesenelib.common
	from emesenecommon import PATH 
	CONFIG_PATH = PATH.CONFIG_DIR

class MyLogger():
	'''Logger able to log in a file the specific conversation'''
	
	def __init__(self,controller,conversation,MainClass,addButton = True):
		'''Save the identifier of this conversation and begin to log message'''
		
		#This identifier enable the check of members change!
		self.members = conversation.getMembers()
		self.idMyLog = self.members[0]
		for mem in self.members[1:len(self.members)]:
			self.idMyLog = self.idMyLog + '-' + mem
		
		#The identifier of this conversation is the id of conversation
		self.idConv = id(conversation)
		self.conversation = conversation
		
		self.mainClass = MainClass
		#self.mainClass.activeLogger.append(self)
		self.stopped = False
		
		self.convId = conversation
		self.controller = controller
		#Every time the conversationManager send a close-conversation-ui 
		#execute stop
		self.convmanagerId = self.controller.conversationManager.connect('close-conversation-ui', self.stop)
		
		
		#We would save logs in : 
		#paths.CONFIG_DIR join controller.config.getCurrentUser() join html_logs
		self.logDir = os.path.join(CONFIG_PATH, \
			controller.config.getCurrentUser()) #this dir exist!
		maybeFaultDir = os.path.join(self.logDir, \
			'html_logs') #This is created at the first run
		
		#If the log dir not exist create it
		if os.path.exists(maybeFaultDir):
			self.logDir = maybeFaultDir
		else:
			os.mkdir(maybeFaultDir)
			# ugly, but "if os.mkdir(..)" doesn't work :S
			if os.path.exists(maybeFaultDir):
				self.logDir = maybeFaultDir
				# if we can't create the dir, we put the file directly 
				# in logDir
		
		
		#Create the log FileName
		self.logFileName = os.path.join(self.logDir, \
			self.idMyLog + '.html')
		
		#Exist already?
		if os.path.exists(self.logFileName):
			self.logFile = open(self.logFileName,'r+')		
			#Ok we have to delete the last string if it is a </body></html>
			self.logFile.seek(-15,2)
			lastLine = self.logFile.readline()
			if lastLine.find('</html>') != -1:
				#Ok, last time we closed the file in the right way
				#let seek  at the beginning of the line to overwrite
				#(15 chars with the new line).
				self.logFile.seek(-15,2)
			else:
				#Last time we have not closed the file in the right way
				#We put a br..
				self.logFile.write('\n<span><br/></span>\n')
		else:
			self.logFile = open(self.logFileName,'w')		
			#Head of the document
			self.logFile.write('<html>\n')
			self.logFile.write('<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n')
			self.logFile.write('<title>Conversation with: ' + self.idMyLog + '</title>\n</head>\n<body>\n')
		
		#self.mainClass.debug('[LogConv] Logging in :' + self.logFileName)
		
		#First string
		self.logFile.write('\n<span><span style=\"font-size: 10pt;font-weight: bold;\"> Started at: ')
		self.logFile.write(time.strftime('%a, %d %b %Y %H:%M:%S', time.localtime(time.time())))
		self.logFile.write('.<br/></span></span>\n')
		self.logFile.flush()
		
		#For file send and receive logging
		self.p2p = controller.msn.p2p[conversation.switchboard.firstUser]
		
		#Connect the sending and receiving logger
		self.sendmessageId = self.controller.conversationManager.connect( \
									'send-message', self.logSendMessage)
		self.receivemessageId = self.controller.conversationManager.connect( \
									'receive-message', self.logReceivedMessage)
		self.receiveOffmessageId = self.mainClass.connect( \
									'offline-message-received', self.logOffReceivedMessage)
		self.fileTransferId = self.p2p.connect('file-transfer-accepted',self.logFileTransfer)
		
		if addButton:
			#Add a button to the toolbar of this conversation:
			self.logButton = gtk.ToolButton()
			self.logButton.set_label(_('Logs'))
			self.logButton.set_stock_id(gtk.STOCK_DND)
			self.logButton.connect('clicked',self.viewLog)
			
			tooltip = gtk.Tooltips()
			tooltip.set_tip(self.logButton, _('View the logs of this conversation'))
			self.logButton.set_tooltip(tooltip)
			
			conversation.ui.input.toolbar.insert(gtk.SeparatorToolItem(), -1)
			conversation.ui.input.toolbar.insert(self.logButton, -1)
			
			conversation.ui.input.toolbar.show_all()
		
		
	def viewLog(self, *args):
		desktop.open(self.logFileName)
		
	def logSendMessage(self, obj, conversation, message):
		'''message is a list of string'''
	
		idThisLog = id(conversation)
		
		#Log this message if the id match	
		if idThisLog == self.idConv:
			#Members have changed??
			members = conversation.getMembers()
			mbThisLog = members[0]
			for mem in members[1:len(members)]:
				mbThisLog = mbThisLog + '-' + mem
			
			if mbThisLog != self.idMyLog:
				self.stop()
				self.__init__(self.controller,self.conversation,self.mainClass,False)
				
			self.appendOutputText(conversation.getUser(), message, 'outgoing')
	
	def logReceivedMessage(self, cm, conversation, mail, nick, message, format, charset):
		
		idThisLog = id(conversation)
		
		#Log this message if the id match	
		if idThisLog == self.idConv:
			#Members have changed??
			members = conversation.getMembers()
			mbThisLog = members[0]
			for mem in members[1:len(members)]:
				mbThisLog = mbThisLog + '-' + mem
			
			if mbThisLog != self.idMyLog:
				self.stop()
				self.__init__(self.controller,self.conversation,self.mainClass,False)
			
			self.appendOutputText(mail, message, 'incoming', \
				conversation.parseFormat(mail, format))
	
	def logOffReceivedMessage(self, msnp, oim):
		'''called when someone sent an offline message'''
		
		user, date, message = oim
		mail = user['addr']

		result = self.controller.conversationManager.getOpenConversation(mail)
		if result != None:
			idThisLog = id(result[1]) #conversation
			if idThisLog == self.idConv:
				self.appendOutputText(mail, message, 'offline_incoming', \
            					time.mktime(date))
	
	def logFileTransfer(self, p2p, session, context, sender):
		
		mail = sender
		#self.mainClass.debug( '[LogConv] Sender of file: %s' % sender)
		
		self.members = self.conversation.getMembers()
		for mem in self.members:
			if (mail == mem) or (mail == 'Me'):
				self.appendOutputText(None, \
            			_('Starting transfer of %s') % context.filename, \
            			'information')
				break
			
	#From in Conversation.py with another end
	def appendOutputText(self, username, text, type, style = None, timestamp = None):
		'''append the given text to the outputFile type is in[incoming:outgoing]'''
		
		if type.startswith('ink_'):
			type = type[4:]
			ink = True
		else:
			ink = False

		if username == self.convId.switchboard.user:
			nick = emesenelib.common.escape(self.controller.msn.nick)
		elif username != None:
			nick = emesenelib.common.escape( \
				self.controller.msn.getUserDisplayName(username))
		else:
			nick = ''

		if timestamp is None:
			timestamp = time.time()

		displayedText = self.controller.conversationLayoutManager.layout(\
			username, text, style, self.convId, type, timestamp, ink)
		
		#erase custom emoticons
		displayedText = self.fromCustomEmoticonsToText(displayedText)
		
		self.logFile.write(displayedText)
		self.logFile.write('\n')
		self.logFile.flush()

	def stop(self, conversationManager = None, conversation = None, window = None):
		'''Close this logger if the id of the conversation closed match with self.idMyLog'''
		
		if self.stopped:
			return
			
		if(conversationManager != None):
			idThisLog = id(conversation)
		else:
			idThisLog = self.idConv
		
		#Close this logger if the id match	
		if idThisLog == self.idConv:
			#Last String
			self.logFile.write('\n<span><span style=\"font-size: 10pt;font-weight: bold;\"> Closed at: ')
			self.logFile.write(time.strftime('%a, %d %b %Y %H:%M:%S',time.localtime(time.time())))
			self.logFile.write('.<br/></span></span>\n')
			#Tail of the document
			self.logFile.write('\n</body></html>\n')
			
			self.logFile.close()
			
			self.controller.conversationManager.disconnect(self.sendmessageId)
			self.controller.conversationManager.disconnect(self.receivemessageId)
			self.controller.conversationManager.disconnect(self.convmanagerId)
			self.mainClass.disconnect(self.receiveOffmessageId)
			self.p2p.disconnect(self.fileTransferId)
			self.stopped = True
	
	def fromCustomEmoticonsToText(self,message):
		
		#This is the string to find and to substitute with the field data
		#'<object type="application/x-emesene-emoticon" class="%s" data="%s"></object>'
		modified = False
		
		firstInstance = message.find('<object')
		#First part of the string where we don't want to see (there are 
		# object tags not custom emoticons)
		offset = 0
		
		if firstInstance < 0:
			#No objects in here.
			return message
		
		while firstInstance >= 0:
			firstInstance += offset
			#find the end of the tag..
			endTag = message[offset:].find('/object>')
			if endTag < 0:
				#Error parsing.. leve what there is
				return message
			
			endTag = offset + endTag + len('/object>')
					
			objectTag = message[firstInstance:endTag]
			fields = objectTag.split('"')
			
			#is a type application/x-emesene-emoticon??
			foundEmoticon = False
			nextIsData = False
			dataField = ''
			for field in fields:
				if nextIsData:
					dataField = field
					nextIsData = False
				if field == 'application/x-emesene-emoticon':
					foundEmoticon = True
				if field.find('data=') >= 0:
					nextIsData = True
			
			if foundEmoticon:
				message1 = message[:firstInstance]
				message2 = message[endTag:]
				message = message1 + dataField + message2
			else:
				offset = endTag
			
			firstInstance = message[offset:].find('<object')
		
		return message
		
		
class MainClass(Plugin.Plugin):
	'''Main plugin class'''

	description = _('Log every session with friendEmail in:\n' +\
					'~/.config/emesene1.0/<address>/html_logs/friendEmail.html')
	authors = { 'Marramao' : 'maramaopercheseimorto@gmail.com'}
	website = 'emesene.org'
	displayName = _('Conversation Logger')
	name = 'LogConversation'
	
	activeLogger = []
	
	def __init__(self, controller, msn):
		'''Contructor'''
		Plugin.Plugin.__init__(self, controller, msn)
		
		self.description = _('Log every session with friendEmail in:\n' +\
					'~/.config/emesene1.0/<address>/html_logs/friendEmail.html')
		self.authors = { 'Marramao' : 'maramaopercheseimorto@gmail.com'}
		self.website = 'emesene.org'
		self.displayName = _('Conversation Logger')
		self.name = 'LogConversation'
		
		self.controller = controller
		self.config = controller.config
		self.config.readPluginConfig(self.name)
		self.enabled = False
		
		self.convmanagerId = 0
		#self.debug( '[LogConv] Initialized.\n')
		
		#self.start()
		
	def start(self):
		'''start the plugin'''
		if self.enabled ==False:
			self.convmanagerId = self.controller.conversationManager.connect( \
				'new-conversation-ui', self.connectLogger)

		self.enabled = True
		
		#self.debug( '[LogConv] Started.\n')

	def connectLogger (self, conversationManager, conversation, window):
		self.newLogger = MyLogger(self.controller,conversation,self)
	

	def stop(self):    
		'''stop the plugin'''
		self.controller.conversationManager.disconnect(self.convmanagerId)
		
		#print '[LogConv]I\'m going to close %d active loggers.' % len(self.activeLogger)
		
		if len(self.activeLogger) > 0:
			for myLogger in self.activeLogger:
				myLogger.stop()
		
		
		self.enabled = False
		#self.debug( '[LogConv] Stopped.\n')

	def check(self):
		return (True, 'Ok')


